unit uDZInetProto;

interface

uses
  SysUtils, Classes, uDZStr;

type
  THttpReqLine = object
  public
    MethodFirst: PAnsiChar;
    MethodLast: PAnsiChar;
    PathFirst: PAnsiChar;
    PathLast: PAnsiChar;
    ParamFirst: PAnsiChar;
    ParamLast: PAnsiChar;
    FileFirst: PAnsiChar;
    FileLast: PAnsiChar;
    VersionFirst: PAnsiChar;
    VersionLast: PAnsiChar;
    function Method: AnsiString;
    function Path: AnsiString;
    function Params: AnsiString;
    function PathAndParams: AnsiString;
    function Version: AnsiString;
    function FileName: AnsiString;
  end;
  PHttpReqLine = ^THttpReqLine;

function HttpParseReqLine(Text: PAnsiChar; TextLen: Integer;
  var ReqLine: THttpReqLine): Boolean; overload;
  
implementation

function HttpParseReqLine(Text: PAnsiChar; TextLen: Integer;
  var ReqLine: THttpReqLine): Boolean;
var
  Str, Seg, TextEnd: PAnsiChar;
begin
  Result := False;
  TextEnd := Text + TextLen;

  //method
  Seg := AnsiSkipChar(Text, TextEnd);
  if Seg = TextEnd then Exit;
  Str := AnsiSeekChar(Seg, TextEnd);
  if Str = TextEnd then Exit;
  ReqLine.MethodFirst := Seg;
  ReqLine.MethodLast := Str;
  
  Seg := AnsiSkipChar(Str, TextEnd);
  if (Seg = TextEnd) or (Seg^ <> '/') then Exit;
  Str := AnsiSeekChar(Seg, TextEnd, [#32, '?']);
  if Str = TextEnd then Exit;

  //path & param
  ReqLine.PathFirst := Seg;
  ReqLine.PathLast := Str;
  if Str^ = #32 then
  begin
    ReqLine.ParamFirst := Str;
    ReqLine.ParamLast := Str;
  end
  else begin
    ReqLine.ParamFirst := Str;
    Str := AnsiSeekChar(Str, TextEnd);
    if Str = TextEnd then Exit;
    ReqLine.ParamLast := Str; 
  end;

  //version
  Seg := AnsiSkipChar(Str, TextEnd);
  if Seg = TextEnd then Exit;
  
  Str := AnsiSeekChar(Seg, TextEnd, [#13]);
  if Str = TextEnd then Exit;
  ReqLine.VersionFirst := Seg;
  ReqLine.VersionLast := Str;

  ReqLine.FileLast := ReqLine.PathLast;
  ReqLine.FileFirst := ReverseSeekChar(ReqLine.PathFirst, ReqLine.PathLast, ['/']) + 1;
  
  Result := True;
end;

{ THttpReqLine }

function THttpReqLine.FileName: AnsiString;
begin
  Result := AnsiStrFromBuf(FileFirst, FileLast - FileFirst);  
end;

function THttpReqLine.Method: AnsiString;
begin
  Result := AnsiStrFromBuf(MethodFirst, MethodLast - MethodFirst);
end;

function THttpReqLine.Params: AnsiString;
begin
  Result := AnsiStrFromBuf(ParamFirst, ParamLast - ParamFirst);
end;

function THttpReqLine.Path: AnsiString;
begin
  Result := AnsiStrFromBuf(PathFirst, PathLast - PathFirst);
end;

function THttpReqLine.PathAndParams: AnsiString;
begin
  Result := AnsiStrFromBuf(PathFirst, ParamLast - PathFirst);
end;

function THttpReqLine.Version: AnsiString;
begin
  Result := AnsiStrFromBuf(VersionFirst, VersionLast - VersionFirst);
end;

end.
